/*
 * JDBCAdapter.java
 *
 * Created on 26 de febrero de 2007, 03:18 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package tablasYBasesdeDatos;

/**
 *
 * @author jose
 */


import everest3.utils.Fecha;
import java.text.DecimalFormat;
import java.util.Vector;
import java.sql.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.event.TableModelEvent;

/**
 * Clase principal que permite realiar consultas hacia la base de datos y poder representar 
 * dicha consulta en una tabla de una manera mas eficiente debido a la implementaci&oacute;n de 
 * la clase AbstractTableModel
 */
public class JDBCAdapter extends AbstractTableModel {
    Connection          connection;
    Statement           statement;
    ResultSet           resultSet;
    String[]            columnNames = {};
    Vector		rows = new Vector();
    ResultSetMetaData   metaData;
    /**
     * vector que recibe los nombre que se desean visualiar los nombre de las columnas de la
     * consulta hacia la base de datos
     */
   public String nombres [] = {};
    /**
     * Constructor principal de la clase que recibre como parametros los atributos para la conexion 
     * con la base de datos
     * @param url direcci&oacute; url del servidor de la base de datos
     * @param driverName nombre del driver de conexi&oacute;n
     * @param user nombre de usuario de la base de datos
     * @param passwd contrase&ntilde;a del usuario de la base de datos
     */
    public JDBCAdapter(String url, String driverName,
                       String user, String passwd) {
        try {
            Class.forName(driverName);
            System.out.println("Opening db connection");

            connection = DriverManager.getConnection(url, user, passwd);
            statement = connection.createStatement();
        }
        catch (ClassNotFoundException ex) {
            System.err.println("Cannot find the database driver classes.");
            System.err.println(ex);
        }
        catch (SQLException ex) {
            System.err.println("Cannot connect to this database.");
            System.err.println(ex);
        }
     }

    /**
     * Constructor por defecto de la clase que no recibe ningun valor por parametro
     */
    public JDBCAdapter (){
        
    }
    /**
     * Este metodo se encarga de asignar los nombres a las columnas de la tabla hacia la que se va a hacer la consulta
     * @param nombres Vector que contiene el nombre de las columnas de la consulta, recuerda que el 
     * tama&ntilde; del vector debe ser igual a la cantidad de columnas de la consulta
     */
    public void asignarNombreColumnas(String nombres[]){
         this.nombres=nombres;
     }
    
    /**
     * Este metodo me permite realizar una consulta en la base de datos, gestionando 
     * un objeto de la clase vector para su representaci&oacute;n en una tabla
     * @param query variable de tipo <CODE>java.lang.String</CODE> que contiene la consulta hacia la 
     * base de datos en formato SQL
     */
    public void executeQuery(String query) {
        if (connection == null || statement == null) {
            System.err.println("There is no database to execute the query.");
            return;
        }
        try {
            resultSet = statement.executeQuery(query);
            metaData = resultSet.getMetaData();

            int numberOfColumns =  metaData.getColumnCount();
            columnNames = new String[numberOfColumns];
            
            // Get the column names and cache them.
            // Then we can close the connection.
            /*ojo para cambiar el nombre de las columnas*/
            for(int column = 0; column < numberOfColumns; column++) {
                columnNames[column] = nombres [column];
            }

            // Get all rows.
            rows = new Vector();
            while (resultSet.next()) {
                Vector newRow = new Vector();
                for (int i = 1; i <= getColumnCount(); i++) {
	            newRow.addElement(resultSet.getObject(i));
                }
                rows.addElement(newRow);
            }
            //  close(); Need to copy the metaData, bug in jdbc:odbc driver.
            fireTableChanged(null); // Tell the listeners a new table has arrived.
        }
        catch (SQLException ex) {
            System.err.println(ex);
        }
    }
    

   
    
    /**
     * Este metodo me permite realizar una consulta en la base de datos, gestionando 
     * un objeto de la clase vector para su representaci&oacute;n en una tabla, ademas 
     * esta metodo asigna un formato definido a determinadas columnas de la tabla a visualizar
     * @param query variable de tipo <CODE>java.lang.String</CODE> que contiene la consulta hacia la 
     * base de datos en formato SQL
     */
    public void consultaConFormato(String query) {
        DecimalFormat df1 = new DecimalFormat("000");
        if (connection == null || statement == null) {
            System.err.println("There is no database to execute the query.");
            return;
        }
        try {
            resultSet = statement.executeQuery(query);
            metaData = resultSet.getMetaData();

            int numberOfColumns =  metaData.getColumnCount();
            columnNames = new String[numberOfColumns];
            
            // Get the column names and cache them.
            // Then we can close the connection.
            /*ojo para cambiar el nombre de las columnas*/
            for(int column = 0; column < numberOfColumns; column++) {
                columnNames[column] = nombres [column];
            }

            // Get all rows.
            rows = new Vector();
            while (resultSet.next()) {
                Vector newRow = new Vector();
                for (int i = 1; i <= getColumnCount(); i++) {
                    if((i==3)||(i==4))
                         newRow.addElement(df1.format(resultSet.getObject(i)));
                    else
                        if((i==2)||(i==7))
                            newRow.addElement(new Fecha().ConvertirHoraAMPM((String) resultSet.getObject(i)));
                        else
                            newRow.addElement(resultSet.getObject(i));
                         
                    
                }
                rows.addElement(newRow);
            }
            //  close(); Need to copy the metaData, bug in jdbc:odbc driver.
            fireTableChanged(null); // Tell the listeners a new table has arrived.
        }
        catch (SQLException ex) {
            System.err.println(ex);
        }
    }
    /**
     * Este metodo me permite realizar una consulta en la base de datos, gestionando 
     * un objeto de la clase vector para su representaci&oacute;n en una tabla, ademas 
     * esta metodo asigna un formato definido a determinadas columnas de la tabla a visualizar
     * @param query variable de tipo <CODE>java.lang.String</CODE> que contiene la consulta hacia la 
     * base de datos en formato SQL
     */
    public void consultaConFormatoRes(String query) {
        DecimalFormat df1 = new DecimalFormat("000");
        if (connection == null || statement == null) {
            System.err.println("There is no database to execute the query.");
            return;
        }
        try {
            resultSet = statement.executeQuery(query);
            metaData = resultSet.getMetaData();

            int numberOfColumns =  metaData.getColumnCount();
            columnNames = new String[numberOfColumns];
            
            // Get the column names and cache them.
            // Then we can close the connection.
            /*ojo para cambiar el nombre de las columnas*/
            for(int column = 0; column < numberOfColumns; column++) {
                columnNames[column] = nombres [column];
            }

            // Get all rows.
            rows = new Vector();
            while (resultSet.next()) {
                Vector newRow = new Vector();
                for (int i = 1; i <= getColumnCount(); i++) {
                    if((i==3)||(i==4))
                    {
                        System.out.println("Num "+i+" Val "+resultSet.getObject(i));
                         newRow.addElement(df1.format(resultSet.getObject(i)));
                    }
                    else
                        if((i==2)||(i==7))
                            newRow.addElement(new Fecha().ConvertirHoraAMPM((String) resultSet.getObject(i)));
                        else
                            newRow.addElement(resultSet.getObject(i));
                         
                    
                }
                rows.addElement(newRow);
            }
            //  close(); Need to copy the metaData, bug in jdbc:odbc driver.
            fireTableChanged(null); // Tell the listeners a new table has arrived.
        }
        catch (SQLException ex) {
            System.err.println(ex);
        }
    }
    /**
     * Este metodo me permite realizar una consulta en la base de datos, gestionando 
     * un objeto de la clase vector para su representaci&oacute;n en una tabla, ademas 
     * esta metodo asigna un formato definido a determinadas columnas de la tabla a visualizar
     * @param query variable de tipo <CODE>java.lang.String</CODE> que contiene la consulta hacia la 
     * base de datos en formato SQL
     */
    public void consultaConFormatoMulta(String query) {
        DecimalFormat df1 = new DecimalFormat("000");
        if (connection == null || statement == null) {
            System.err.println("There is no database to execute the query.");
            return;
        }
        try {
            resultSet = statement.executeQuery(query);
            metaData = resultSet.getMetaData();

            int numberOfColumns =  metaData.getColumnCount();
            columnNames = new String[numberOfColumns];
            
            // Get the column names and cache them.
            // Then we can close the connection.
            /*ojo para cambiar el nombre de las columnas*/
            for(int column = 0; column < numberOfColumns; column++) {
                columnNames[column] = nombres [column];
            }

            // Get all rows.
            rows = new Vector();
            while (resultSet.next()) {
                Vector newRow = new Vector();
                for (int i = 1; i <= getColumnCount(); i++) {
                     if((i==3)||(i==4))
                         newRow.addElement(df1.format(resultSet.getObject(i)));
                     else
                       if(i==2)
                            newRow.addElement(new Fecha().ConvertirHoraAMPM((String) resultSet.getObject(i)));
                        else
                            newRow.addElement(resultSet.getObject(i));
                         
                    
                }
                rows.addElement(newRow);
            }
            //  close(); Need to copy the metaData, bug in jdbc:odbc driver.
            fireTableChanged(null); // Tell the listeners a new table has arrived.
        }
        catch (SQLException ex) {
            System.err.println(ex);
        }
    }
    
    Vector newRow; 
    /**
     * Este metodo me permite realizar una consulta en la base de datos, gestionando 
     * un objeto de la clase vector que contiene el numero de columnas asociados al
     * registro de busqueda
     * @param query variable de tipo <CODE>java.lang.String</CODE> que contiene la consulta hacia la 
     * base de datos en formato SQL
     * @return Objeto de la clase <CODE>java.util.Vector</CODE> que contiene el resultado de la consulta
     * previamente realizada
     */
    public java.util.Vector ConsultaIndividual(String query) {
        if (connection == null || statement == null) {
            System.err.println("There is no database to execute the query.");
            return new Vector();
        }
        try {
            resultSet = statement.executeQuery(query);
            metaData = resultSet.getMetaData();

         //  System.out.print(query);
            // Get the column names and cache them.
            // Then we can close the connection.
            /*ojo para cambiar el nombre de las columnas*/
           
            // Get all rows.
            newRow = new Vector();
            while (resultSet.next()) {
                
                for (int i = 1; i <= metaData.getColumnCount(); i++) {
	            newRow.addElement(resultSet.getObject(i));
                    
                }
               
            }
           
            
        }
        catch (SQLException ex) {
            System.err.println(ex);
        }
        
      
        return newRow;
    }
    java.util.Vector resultado;
    /**
     * Este metodo me permite realizar una consulta en la base de datos, gestionando 
     * un objeto de la clase vector que contiene todas las filas asociadas a la consulta
     * @param query variable de tipo <CODE>java.lang.String</CODE> que contiene la consulta hacia la 
     * base de datos en formato SQL
     * @return Objeto de la clase <CODE>java.util.Vector</CODE> que contiene el resultado de la consulta
     * previamente realizada
     */
      public java.util.Vector consultaCampos(String query) {
        if (connection == null || statement == null) {
            System.err.println("There is no database to execute the query.");
            return null;
        }
        try {
            resultSet = statement.executeQuery(query);
            metaData = resultSet.getMetaData();
           
            // Get all rows.
            resultado = new Vector();
            while (resultSet.next()) {                
	            resultado.addElement(Integer.parseInt(resultSet.getString(1)));           
               
            }
           
        }
        catch (SQLException ex) {
            System.err.println(ex);
        }
        
       
        return resultado;
    }

    /**
     * Este metodo me permite gestiona el cierre de la consulta SQL para poder realizar 
     * una mejor gestion de los recursos de memoria en tiempo de ejecuci&oacute;n
     * @throws java.sql.SQLException Este excepcion se gernera cuando se produce un error en el momento de cerrar
     * la conexi&oacute;n hacia la base de datos
     */
    public void close() throws SQLException {
        System.out.println("Closing db connection");
        resultSet.close();
        statement.close();
        connection.close();
    }

    /**
     * Este metodo me permite gestiona el cierre del la conexion de la base
     * de datos
     * @throws java.lang.Throwable Excepcion que se captura para el buen comportamiento del sistema
     */
    protected void finalize() throws Throwable {
        close();
        super.finalize();
    }

    //////////////////////////////////////////////////////////////////////////
    //
    //             Implementation of the TableModel Interface
    //
    //////////////////////////////////////////////////////////////////////////

    // MetaData

    /**
     * permite obtener el nombre de las columnas de la base de datos
     * @param column numero de la columna
     * @return valor del nombre de la columna
     */
    public String getColumnName(int column) {
        if (columnNames[column] != null) {
            return columnNames[column];
        } else {
            return "";
        }
    }

    /**
     * determina el tipo de datos en la columna
     * @param column numero de columna
     * @return tipo de dato de la columna deseada
     */
    public Class getColumnClass(int column) {
        int type;
        try {
            type = metaData.getColumnType(column+1);
        }
        catch (SQLException e) {
            return super.getColumnClass(column);
        }

        switch(type) {
        case Types.CHAR:
        case Types.VARCHAR:
        case Types.LONGVARCHAR:
            return String.class;

        case Types.BIT:
            return Boolean.class;

        case Types.TINYINT:
        case Types.SMALLINT:
        case Types.INTEGER:
            return Integer.class;

        case Types.BIGINT:
            return Long.class;

        case Types.FLOAT:
        case Types.DOUBLE:
            return Double.class;

        case Types.DATE:
            return java.sql.Date.class;

        default:
            return Object.class;
        }
    }

    /**
     * metodo que permite determinar si una celda o un afila del modelo de la tabla es editable o no
     * @param row numero de fila
     * @param column numero de columna
     * @return true si dicha celda es o no editable, false en caso contrario
     */
    public boolean isCellEditable(int row, int column) {
        try {
            return metaData.isReadOnly(column+1);// tabla de solo lectura
        }
        catch (SQLException e) {
            return false;
        }
    }

    /**
     * metodo que permite determinar la cantidad de columnas de la tabla
     * @return numero de columnas de la tabla
     */
    public int getColumnCount() {
        return columnNames.length;
    }

    // Data methods

    /**
     * metodo que permite determinar la cantidad de filas de la tabla
     * @return numero de filas de la columna
     */
    public int getRowCount() {
        return rows.size();
    }

    /**
     * metodo que permite obtener el valor de la tabla en determinada posicion
     * @param aRow numero de fila
     * @param aColumn numero de columna
     * @return Objeto con el valor en la celda
     */
    public Object getValueAt(int aRow, int aColumn) {
        Vector row = (Vector)rows.elementAt(aRow);
        return row.elementAt(aColumn);
    }

    /**
     * metodo que permite la representacion del formato de los valores de la consulta en la tabla
     * @param column numero de la columna
     * @param value valor a determinar formato
     * @return formato de visualizaci&iacute;n
     */
    public String dbRepresentation(int column, Object value) {
        int type;

        if (value == null) {
            return "null";
        }

        try {
            type = metaData.getColumnType(column+1);
        }
        catch (SQLException e) {
            return value.toString();
        }

        switch(type) {
        case Types.INTEGER:
        case Types.DOUBLE:
        case Types.FLOAT:
            return value.toString();
        case Types.BIT:
            return ((Boolean)value).booleanValue() ? "1" : "0";
        case Types.DATE:
            return value.toString(); // This will need some conversion.
        default:
            return "\""+value.toString()+"\"";
        }

    }
    
    /**
     * Este metodo me permite realizar una consulta en la base de datos, gestionando 
     * un objeto de la clase vector para su representaci&oacute;n en una tabla, ademas 
     * esta metodo asigna un formato definido a determinadas columnas de la tabla a visualizar
     * @param sql variable de tipo <CODE>java.lang.String</CODE> que contiene la consulta hacia la 
     * base de datos en formato SQL
     */
    public void consultaConFormatoMaterialBibliog(String sql) {
         DecimalFormat df1 = new DecimalFormat("000");
        if (connection == null || statement == null) {
            System.err.println("There is no database to execute the query.");
            return;
        }
        try {
            resultSet = statement.executeQuery(sql);
            metaData = resultSet.getMetaData();

            int numberOfColumns =  metaData.getColumnCount();
            columnNames = new String[numberOfColumns];
            
            // Get the column names and cache them.
            // Then we can close the connection.
            /*ojo para cambiar el nombre de las columnas*/
            for(int column = 0; column < numberOfColumns; column++) {
                columnNames[column] = nombres [column];
            }

            // Get all rows.
            rows = new Vector();
            while (resultSet.next()) {
                Vector newRow = new Vector();
                for (int i = 1; i <= getColumnCount(); i++) {
                    if((i==1)||(i==2))
                         newRow.addElement(df1.format(resultSet.getObject(i)));              
                        else
                            newRow.addElement(resultSet.getObject(i));
                         
                    
                }
                rows.addElement(newRow);
            }
            //  close(); Need to copy the metaData, bug in jdbc:odbc driver.
            fireTableChanged(null); // Tell the listeners a new table has arrived.
        }
        catch (SQLException ex) {
            System.err.println(ex);
        }
    } 
}
